package com.com.effectivejava.generalprogramming;

import java.util.*;

/**
 * Created by User on 08/07/2014.
 */
public class ForEachVSForLoop {
    //Beware of iterator.next() use in multi loop.
    // Implement iterable for collection of user defined types. and use these loops.

    static enum Suit { CLUB, DIAMOND, HEART, SPADE };

    static enum Rank { ACE, DEUCE, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT,
        NINE, TEN, JACK, QUEEN, KING };

    static enum Face { ONE, TWO, THREE, FOUR, FIVE, SIX };

    static class Card{
        Card(Suit suit, Rank rank){}
    }

    static public void forEachVSForLoopIncorrect(){

        Collection<Suit> suits = Arrays.asList(Suit.values());
        Collection<Rank> ranks = Arrays.asList(Rank.values());

        List<Card> deck = new ArrayList<Card>();
        /* problem with the for loop. i.next() returns the next element from the list.*/
        for (Iterator<Suit> i = suits.iterator(); i.hasNext(); )
            for (Iterator<Rank> j = ranks.iterator(); j.hasNext(); )
                deck.add(new Card(i.next(), j.next()));
    }

    static public void forEachVSForLoopCorrect(){
        Collection<Suit> suits = Arrays.asList(Suit.values());
        Collection<Rank> ranks = Arrays.asList(Rank.values());

        List<Card> deck = new ArrayList<Card>();
        /* problem with the for loop. i.next() returns the next element from the list.*/
        for (Iterator<Suit> i = suits.iterator(); i.hasNext(); ){
            Suit s = i.next();
            for (Iterator<Rank> j = ranks.iterator(); j.hasNext(); )
                deck.add(new Card(s, j.next()));
        }
    }

    static public void forEachVSForLoopBetterOption(){
        Collection<Suit> suits = Arrays.asList(Suit.values());
        Collection<Rank> ranks = Arrays.asList(Rank.values());

        List<Card> deck = new ArrayList<Card>();
        for(Suit s : suits){
            for(Rank r : ranks ){
                deck.add(new Card(s, r));
            }
        }
    }

    public static void main(String... a){

        //forEachVSForLoopIncorrect(); //incorrect for loop.
        forEachVSForLoopCorrect(); // correct for loop.
        forEachVSForLoopBetterOption(); //better option.

        hardToSpotBugAndItsBetterSolution(); // good lesson.
    }

    // Good Lesson.
    static public void hardToSpotBug(){
        Collection<Face> faces = Arrays.asList(Face.values());
        for (Iterator<Face> i = faces.iterator(); i.hasNext(); )
            for (Iterator<Face> j = faces.iterator(); j.hasNext(); )
                System.out.println(i.next() + " " + j.next());

    }
    static public void hardToSpotBugAndItsSolution(){
        Collection<Face> faces = Arrays.asList(Face.values());
        for (Iterator<Face> i = faces.iterator(); i.hasNext(); ){
            Face f = i.next();
            for (Iterator<Face> j = faces.iterator(); j.hasNext(); )
                System.out.println(f + " " + j.next());

        }
    }
    static public void hardToSpotBugAndItsSolutionUsingForEach(){
        Collection<Face> faces = Arrays.asList(Face.values());
        for(Face f : faces ){
            for(Face f2 : faces){
                System.out.print(f + " " + f2);
            }
        }
    }
    static public void hardToSpotBugAndItsBetterSolution(){
        hardToSpotBug();
        hardToSpotBugAndItsSolution();
        hardToSpotBugAndItsSolutionUsingForEach();
    }
}
